//////////////////////////////////////////////////////////////////////////////
//////	File: main.cpp
//////
//////	Author:	Omar Khan
//////
//////	Created: January 11, 2010
//////
//////	Purpose: Application framework that will create the window, update, 
//////			 and render the game as well as clean up as necessary
//////////////////////////////////////////////////////////////////////////////

#include <windows.h>
#include <iostream>
#include <ctime>

#include "Render.h"
#include "Timer.h"

using namespace std;

#define			SCREEN_WIDTH		1024
#define			SCREEN_HEIGHT		768
#define			FRAME_RATE          0.033f // 0.1 (10fps) 0.033 (30fps)



HINSTANCE   app;
HWND        wnd;

// main d3d COM objects
IDirect3D9			*d3d;
IDirect3DDevice9	*dev;



Timer	myTimer;
float	frame = 0;		// animation frame


void InitGame();
void LoopGame();
void EndGame();

void Update(float gameTime);
void Render();

// Classes for rendering and camera
CRender render;






int WINAPI WinMain(HINSTANCE hInstance,		// handle to application
				   HINSTANCE hPrevInstance,	// handle to previous app
				   LPTSTR lpCmdLine,		// command line string
				   int nCmdShow );			// show window value

LRESULT CALLBACK WndProc(HWND hWnd,				// handle to window
						 UINT message,			// incoming message
						 WPARAM wparam,			// message info
						 LPARAM lparam );		// message info

bool InitWindow(void);						// initialize window
void ResizeWindow(HWND hWnd, int width, int height);

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE, LPTSTR, int )
{
    app = hInstance;				// store application handle

	srand(unsigned int(time(0)));	//randomize!

    InitWindow();					// get window
	InitGame();						// initialize game

	// Creating Class to draw the infromation
	render.Init(dev, wnd);




    // use to catch windows messages
    MSG msg; ZeroMemory( &msg, sizeof( msg ) );
    while ( msg.message != WM_QUIT )
    {
		// Call the gameloop once per frame
		LoopGame();

		// get any system messages
        if ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
        { 
            TranslateMessage( &msg );
            DispatchMessage( &msg ); 
        }
    }

	EndGame();						// clean up after game ends

	// window cleanup
	UnregisterClass( "DirectXApplication", app ); // unregister window
    return 0;		// done
}

LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
    // attempt to handle
    switch ( message )
    {
        case ( WM_DESTROY ): { PostQuitMessage( 0 ); }
        break;
    }
    // pass to default handler
    return DefWindowProc( hWnd, message, wParam, lParam );
}

bool InitWindow( void )
{   
    WNDCLASSEX  wndClass;

    // register a new type of window
    ZeroMemory( &wndClass, sizeof( wndClass ) );
    wndClass.cbSize         = sizeof( WNDCLASSEX );             // size of window structure
    wndClass.lpfnWndProc    = ( WNDPROC )WndProc;               // message callback
    wndClass.lpszClassName  = "DirectXApplication";             // class name
    wndClass.hInstance      = app			;                   // handle to application
    wndClass.hCursor        = LoadCursor( NULL, IDC_ARROW );    // default cursor
    wndClass.hbrBackground  = ( HBRUSH )( COLOR_WINDOWFRAME );  // background brush
    RegisterClassEx( &wndClass );

    // create window of registered type
    wnd = CreateWindow(
        "DirectXApplication", "DirectX Application",            // class name, window title 
		WS_OVERLAPPEDWINDOW,									// window style
        CW_USEDEFAULT, CW_USEDEFAULT,                           // x & y coordinates
        SCREEN_WIDTH, SCREEN_HEIGHT,                            // width & height of window
        NULL, NULL,                                             // parent window & menu
        app,							                      // handle to application
        NULL );

	ResizeWindow(wnd, SCREEN_WIDTH, SCREEN_HEIGHT);
    ShowWindow( wnd, SW_SHOW );                           // technically should be nCmdShow
    UpdateWindow( wnd );
    return true;
}

/*
* ResizeWindow
* resizes the client area of a window to be a specific width and height
*/
void ResizeWindow(HWND hWnd, int width, int height)
{  
	// get the size of the current client area
	RECT rcClient;
	GetClientRect(hWnd, &rcClient);
  
	// get the size of the containing window
	RECT rcWindow;
	GetWindowRect(hWnd, &rcWindow);
  
	// determine the difference between the two
	POINT diff;
	diff.x = (rcWindow.right - rcWindow.left) - rcClient.right;
	diff.y = (rcWindow.bottom - rcWindow.top) - rcClient.bottom;
	// resize the client area
	MoveWindow(hWnd,rcWindow.left, rcWindow.top, width + diff.x, height + diff.y, TRUE);
}

/*
* InitGame()
* Called when the game is starting. Handles gameobject inits
*/
void InitGame()
{
		

	// create d3d obj
	d3d = Direct3DCreate9(D3D_SDK_VERSION);

	// present parametes
	D3DPRESENT_PARAMETERS d3dpp;
	ZeroMemory(&d3dpp, sizeof(D3DPRESENT_PARAMETERS));
	d3dpp.BackBufferWidth            = SCREEN_WIDTH;
	d3dpp.BackBufferHeight           = SCREEN_HEIGHT;
	d3dpp.BackBufferFormat           = D3DFMT_A8R8G8B8;
	d3dpp.BackBufferCount            = 1;
	d3dpp.hDeviceWindow = wnd;
	d3dpp.Windowed		= true;
	d3dpp.PresentationInterval	= D3DPRESENT_INTERVAL_IMMEDIATE;
	d3dpp.SwapEffect			= D3DSWAPEFFECT_DISCARD;

	// add for 3D
	// depth /stencil
	// stencil format
	d3dpp.EnableAutoDepthStencil = true;
	d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;

	// create the D3Ddevice
	d3d->CreateDevice(0, D3DDEVTYPE_HAL, wnd,
		D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &dev);

	// reset the timer
	myTimer.Reset();
}


/*
* LoopGame()
* This is the main game loop
*/
void LoopGame()
{
	//static float prevTime = 0.0f;

	// get the amount of time that passed since last frame
	float gameTime = myTimer.GetDeltaTime();
//	prevTime += gameTime;

	//if(prevTime > FRAME_RATE)	// time since last update
	//{
		// update gameobjects
	Update(gameTime);
	Render();

	//	prevTime = 0;	// start counting again
	//}


	// update the timer
	myTimer.Update();
}

/*
* Update(float gameTime)
* Called each frame. Updating of gameobjects go here
*/
void Update(float gameTime)
{
	render.Update(gameTime, dev);
}

/*
* Render()
* Called each frame. Drawing goes here
*/
void Render()
{
	render.Render(dev);
}


/*
* EndGame()
* Called when the game is being shutdown
*/
void EndGame()
{

	render.Cleanup();
	// release the d3d object and device
	if (dev != NULL)
	{
		dev->Release();	
		dev = NULL;
	}
	if (d3d != NULL)
	{
		d3d->Release();	
		d3d = NULL;
	}
}
